package gen

import (
	"bytes"
	"fmt"
	"os"
	"text/template"

	"gitee.com/krio/ginc/parse"
	"gitee.com/krio/ginc/util"
)

const (
	routePackageName = "route"  // 包名称
	routeImportName  = "import" // 包引用
)

// GenRoute 生成路由地址常量
func (g *Generator) GenRoute() error {
	// 先删除目录下所有文件
	_ = os.RemoveAll(g.ToRoute)
	err := os.MkdirAll(g.ToRoute, os.ModePerm)
	if err != nil {
		return err
	}
	// 先生成必要的文件
	err = g.GenRouteBasics()
	if err != nil {
		return err
	}
	for _, v := range g.protoList {
		err = g.genRoute(v)
		if err != nil {
			return err
		}
	}

	return nil
}

func (g *Generator) genRoute(info *parse.ParseProtoInfo) error {
	if len(info.ApiList) == 0 {
		return nil
	}
	genFilePath := fmt.Sprintf("%s/%s_gen.go", g.ToRoute, util.PascalToSnake(info.Service.Name))
	f, err := util.Create(genFilePath)
	if err != nil {
		return err
	}
	defer f.Close()
	var (
		apiLen          = len(info.ApiList)
		contents        = fmt.Sprintf("package %s\n\n", routePackageName)
		roueList        = make([]string, 0, apiLen)
		importList      = make([]string, 0, apiLen)
		importVarString = " {{.CtlImportAs}} \"{{.CtlImport}}\" \n"
		// import定义string
		routeVarString = `
var {{.ServiceName}}{{.Name}}{{.Method}}  = Register(
		"{{.URL}}",
		"{{.ServiceDesc}}-{{.Desc}}",
		"{{.Method}}",
		{{.CtlImportAs}}.{{.Name}},
		{{.MiddlewareString}},
		{{.RoleString}},
		"{{.Output}}",
		{{.LimiterString}}
	)

`
	)
	// 处理引用
	tmpl1 := template.Must(template.New(routeImportName).Parse(importVarString))
	for _, v := range info.ApiList {
		v.CtlImport = info.GenData.HandlerImportUrl
		v.CtlImportAs = info.GenData.HandlerImportAs
		var buf bytes.Buffer
		err = tmpl1.Execute(&buf, v)
		if err != nil {
			return fmt.Errorf("template execute failed. err=%+v", err)
		}
		importList = append(importList, buf.String())
	}
	// 处理api
	tmpl2 := template.Must(template.New(routePackageName).Parse(routeVarString))
	for _, v := range info.ApiList {
		var buf bytes.Buffer
		err = tmpl2.Execute(&buf, v)
		if err != nil {
			return fmt.Errorf("template execute failed. err=%+v", err)
		}
		roueList = append(roueList, buf.String())
	}
	// 这里处理下排序
	util.SortStrings(importList)
	contents += "import (\n"
	for _, v := range importList {
		contents += v
	}
	contents += ")\n\n"
	// 这里处理下排序
	util.SortStrings(roueList)
	for _, v := range roueList {
		contents += v
	}
	_, err = f.WriteString(contents)
	if err != nil {
		return err
	}
	if err = util.FormatGoCode(genFilePath); err != nil {
		return fmt.Errorf("gofmt code failed. err=%+v", err)
	}
	return nil
}

type RouteBasics struct {
	PackageName string `json:"package_name"` // 包名称
}

// GenRouteBasics 生成路由基本定义内容
// 检查和生成 route_basic_gen.go 文件
func (g *Generator) GenRouteBasics() error {
	content := `package {{.PackageName}}

// 【 *** 此文件为自动生成，禁止私加代码 *** 】

var apiRouteList []IApiRoute

type ApiRoute struct {
	URL         string      // 路由URL
	Name        string      // 路由名称
	Method      string      // 路由名称
	Middlewares []string    // 路由中间件
	Roles       []string    // 路由权限组
	Output   string      // 接口处理器
	Limiter     LimitOption // 接口限流器
	Func        interface{} // 接口实现函数
}

type LimitOption struct {
	Type         string // 限流器类型
	Mode         string // 限流模式
	Cap          int64  // 容量数
	IntervalTime int64  // 令牌间隔时间(毫秒)
	ExpireTime   int64  // 令牌过期时间(毫秒)
}

// Register 注册api
func Register(
	url, name, method string,
	f interface{},
	middlewares, roles []string,
	output string,
	limiter LimitOption,
) IApiRoute {
	if url == "" {
		panic("路由URL不能为空")
	}
	ar := ApiRoute{
		URL:         url,
		Name:        name,
		Method:      method,
		Func:        f,
		Middlewares: middlewares,
		Roles:       roles,
		Output:      output,
		Limiter:     limiter,
	}
	apiRouteList = append(apiRouteList, ar)
	return ar
}

// GetGenApiRouteList 获取所有的api路由的数据列表
func GetGenApiRouteList() []IApiRoute {
	return apiRouteList
}

// GetRouteByURL 通过路由获取接口配置信息
func GetRouteByURL(url string) IApiRoute {
	for _, route := range apiRouteList {
		if route.GetURL() == url {
			return route
		}
	}
	return nil
}

type IApiRoute interface {
	GetInfo() ApiRoute
	GetName() string
	GetURL() string
	GetFunc() interface{}
}

func (a ApiRoute) GetInfo() ApiRoute {
	return a
}

func (a ApiRoute) GetName() string {
	return a.Name
}

func (a ApiRoute) GetURL() string {
	return a.URL
}

func (a ApiRoute) GetFunc() interface{} {
	return a.Func
}
`
	data := &RouteBasics{
		PackageName: routePackageName,
	}
	tmpl := template.Must(template.New(routePackageName).Parse(content))
	var buf bytes.Buffer
	err := tmpl.Execute(&buf, data)
	if err != nil {
		return fmt.Errorf("template execute failed. err=%+v", err)
	}
	filePath := g.ToRoute + "/api_basic_gen.go"
	f, err := util.Create(filePath)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.WriteString(buf.String())
	if err != nil {
		return err
	}
	if err = util.FormatGoCode(filePath); err != nil {
		return fmt.Errorf("gofmt code failed. err=%+v", err)
	}
	return nil
}
